package cn.fastpay.management.security;

import cn.fastpay.core.exception.BaseException;
import cn.fastpay.core.vo.LoginUser;
import cn.fastpay.management.exception.PermissionOperatorException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;


import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collections;
import java.util.Date;

/**
 * Jwt 鉴权组件
 * @author freewolf
 */
public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    private Long expireTime;
    private String secret;

    private AuthenticationManager authenticationManager;

    public JwtAuthenticationFilter(AuthenticationManager authenticationManager, String secret, Long expireTime, String loginUrl) {
        this.authenticationManager = authenticationManager;
        this.expireTime = expireTime;
        this.secret = secret;

        this.setFilterProcessesUrl(loginUrl);
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res) throws AuthenticationException {
        try {
            // String reqestBody = StreamUtils.copyToString(req.getInputStream(), Charset.forName("UTF-8"));
            // System.out.println(reqestBody);
            // PermissionOperator operator = new ObjectMapper().readValue(req.getInputStream(), PermissionOperator.class);
            LoginUser user = new ObjectMapper().readValue(req.getInputStream(), LoginUser.class);

            return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(
                    user.getUsername(), user.getPassword(), Collections.emptyList())
            );

        } catch (BadCredentialsException e) {
            throw PermissionOperatorException.OPERATOR_PASSWORD_WRONG;
        } catch (UsernameNotFoundException e){
            throw PermissionOperatorException.OPERATOR_NOT_FOUND;
        } catch (Exception e) {
            throw BaseException.UNKNOWN_ERROR;
        }
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest req, HttpServletResponse res, FilterChain chain,
                                            Authentication auth) throws IOException, ServletException {

        String token = Jwts.builder()
                .setSubject(((User) auth.getPrincipal()).getUsername())
                .setExpiration(new Date(System.currentTimeMillis() + expireTime))
                .signWith(SignatureAlgorithm.HS512, secret.getBytes())
                .claim("claims", auth.getAuthorities())
                .compact();
        // 这里可以优化一下
        res.getWriter().println("{\"code\": 0, \"message\": \"success\", \"data\": \""+ token +"\"}");
    }
}

